import { ref, onMounted, onUnmounted, reactive } from "vue";

interface IRect {
  top: number;
  left: number;
  bottom: number;
  right: number;
  height: number;
  width: number;
}

const initRect: IRect = {
  top: NaN,
  left: NaN,
  bottom: NaN,
  right: NaN,
  height: NaN,
  width: NaN,
};

export interface IState extends IRect {
  text: string;
}

const initState: IState = {
  text: '',
  ...initRect,
};

function getRectFromSelection(selection: Selection | null): IRect {
  if (!selection) {
    return initRect;
  }

  if (selection.rangeCount < 1) {
    return initRect;
  }
  const range = selection.getRangeAt(0);
  const { height, width, top, left, right, bottom } = range.getBoundingClientRect();
  return {
    height,
    width,
    top,
    left,
    right,
    bottom,
  };
}

export function useTextSelection(isBody = false) {
  const el = ref(null);
  let dom: HTMLElement;
  let selection: IState = reactive(JSON.parse(JSON.stringify(initState)));

  function _onMouseDown() {
    const selObj = window.getSelection();
    if (!selObj) return;
    selObj.removeAllRanges();
    selection.top = initState.top;
    selection.left = initState.left;
    selection.bottom = initState.bottom;
    selection.right = initState.right;
    selection.height = initState.height;
    selection.width = initState.width;
    selection.text = initState.text;
  }

  function _onMouseUp() {
    let selObj: Selection | null = null;
    let text = '';
    let rect = initRect;
    selObj = window.getSelection();
    text = selObj ? selObj.toString() : '';
    if (text) {
      rect = getRectFromSelection(selObj);
    }

    selection.top = rect.top;
    selection.left = rect.left;
    selection.bottom = rect.bottom;
    selection.right = rect.right;
    selection.height = rect.height;
    selection.width = rect.width;
    selection.text = text;
  }

  onMounted(() => {
    if (!window.getSelection) return;
    if (!isBody && !el.value) return;
    dom = isBody ? document.body : el.value as unknown as HTMLElement

    document.addEventListener('mousedown', _onMouseDown);
    dom.addEventListener("mouseup", _onMouseUp);
  })

  onUnmounted(() => {
    document.removeEventListener('mousedown', _onMouseDown);
    dom.removeEventListener("mouseup", _onMouseUp);
  })

  return { el, selection }
}